#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include "Acceptor.h"
#include "../Log/log.h"
#include "InetAddress.h"
#include <fcntl.h>
/*serverfd是在这里创建的?*/
static int createNonblocking()
{
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
   
    if (sockfd < 0)
    {
        LOG_ERROR("listen socket create err [%d] ",errno);
    }
    return sockfd;
}


Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reuseport)
    : loop_(loop)
    , acceptSocket_(createNonblocking())
    , acceptChannel_(loop, acceptSocket_.fd())
    , listenning_(false)
{
    //LOG_INFO("server id:[%d]",acceptSocket_.fd());
    //LOG_INFO("Acceptor make success");
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.setReusePort(true);
    acceptSocket_.bindAddress(listenAddr);
    // TcpServer::start() => Acceptor.listen() 如果有新用户连接 要执行一个回调(accept => connfd => 打包成Channel => 唤醒subloop)
    // baseloop监听到有事件发生 => acceptChannel_(listenfd) => 执行该回调函数
    acceptChannel_.setReadCallback(
        std::bind(&Acceptor::handleRead, this));
}

Acceptor::~Acceptor()
{
    acceptChannel_.disableAll();    // 把从Poller中感兴趣的事件删除掉
    acceptChannel_.remove();        // 调用EventLoop->removeChannel => Poller->removeChannel 把Poller的ChannelMap对应的部分删除
}

void Acceptor::listen()
{
    listenning_ = true;
    acceptSocket_.listen();         // 开启listen
    acceptChannel_.enableReading(); // acceptChannel_注册至Poller,要不怎么监听呢
}


// listenfd有事件发生了，就是有新用户连接了
void Acceptor::handleRead()
{
    InetAddress peerAddr;
    do
    {
        int connfd = acceptSocket_.accept(&peerAddr);
        if(connfd < 0)
            break;
        //LOG_INFO("listen fd:[%d] success",connfd);

        //fcntl(connfd, F_SETFL, fcntl(connfd, F_GETFD, 0) | O_NONBLOCK);(不用 已经设计过了)
        if (connfd >= 0)
        {
            if (NewConnectionCallback_) /*Tcp Server中调用的*/
            {
                NewConnectionCallback_(connfd, peerAddr); // 轮询找到subLoop 唤醒并分发当前的新客户端的Channel
            }
            else
            {
                ::close(connfd);
            }
        }
        else
        {
            LOG_ERROR("accept Err");
            if (errno == EMFILE)
            {
                LOG_ERROR("sockfd reached limit");
            }
        }
    } while (true);
    
}
